﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using SaveCurrentState.Util;
using System.Drawing;

namespace ManageWorkingState {
    public class XmlResourceHelper {
        #region constants
        private const string ROOT_TAG_NAME = "Files";
        private const string FILE_TAG_NAME = "File";
        private const string NAME_TAG_NAME = "FileName";
        private const string PATH_TAG_NAME = "FilePath";
        private const string TYPE_TAG_NAME = "Type";
        private const string CHECKED_OPEN_TAG_NAME = "CheckedOpen";
        private const string ADDITION_INFO_TAG = "AdditionInfo";
        private const string POSITION_TAG = "Position";
        private const string POSITION_OFF_TAG = "PositionOf";
        private const string X_TAG = "X";
        private const string Y_TAG = "Y";
        #endregion
        #region Fields
        private readonly string AppDataFolder;
        private readonly string AppDataFile;
        
        private XDocument m_xmlDoc;
        private static XmlResourceHelper s_instance;

        #endregion

        #region constructors

        public XmlResourceHelper() {
            AppDataFolder = Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) + @"\" + Constants.AppName;
            AppDataFile =  AppDataFolder +  @"\StoreStateData.xml";
            LoadResource();
        }

        #endregion

        #region Public Function

        public static XmlResourceHelper GetInstance() {
            if (s_instance == null) {
                s_instance = new XmlResourceHelper();
            }

            return s_instance;
        }

        public void LoadResource() {
            if (!File.Exists(AppDataFile)) {
                CreateXmlDataFile();
            }

            // Read data file
            m_xmlDoc = XDocument.Load(AppDataFile);
        }

        public IList<GridFileFolderItem> GetAllRecordFromXml() {
            var fRecordItems = from file in m_xmlDoc.Elements(ROOT_TAG_NAME).Elements(FILE_TAG_NAME)
                               select new GridFileFolderItem {
                            Name = file.Element(NAME_TAG_NAME).Value,
                            Path = file.Element(PATH_TAG_NAME).Value,
                            Type = file.Element(TYPE_TAG_NAME).Value,
                            AllowOpenDefault = StringToBoolOrDefault(file.Element(CHECKED_OPEN_TAG_NAME))
                        };

            return fRecordItems.ToList();
        }


        public void AddANode(string fileName, string filePath, string type, bool CheckedToOpen) {
            var fileItem = new XElement(FILE_TAG_NAME);
            fileItem.Add(new XElement(NAME_TAG_NAME, fileName));
            fileItem.Add(new XElement(PATH_TAG_NAME, filePath));
            fileItem.Add(new XElement(TYPE_TAG_NAME, type));
            fileItem.Add(new XElement(CHECKED_OPEN_TAG_NAME, BoolToString(CheckedToOpen)));
            m_xmlDoc.Element(ROOT_TAG_NAME).Add(fileItem);
        }

        public void RemoveANode(string fileName, string filePath) {
            m_xmlDoc.Elements(ROOT_TAG_NAME).Elements(FILE_TAG_NAME).
                Where(x => (x.Element(NAME_TAG_NAME).Value == fileName) &&
                    (x.Element(PATH_TAG_NAME).Value == filePath)).Remove();
        }

        public void UpdateANode(string oldPath, string fileName, string filePath, string type, bool CheckedToOpen) {
            var element = m_xmlDoc.Elements(ROOT_TAG_NAME).Elements(FILE_TAG_NAME).
                Where(x=>
                    (x.Element(PATH_TAG_NAME).Value == filePath)).Single() ;


            if (element != null) {
                element.Element(NAME_TAG_NAME).Value = fileName;
                element.Element(PATH_TAG_NAME).Value = filePath;
                element.Element(TYPE_TAG_NAME).Value = type;
                element.Element(CHECKED_OPEN_TAG_NAME).Value = BoolToString(CheckedToOpen);
            }
        }

        public void SaveXmlData() {
            m_xmlDoc.Save(AppDataFile);
        }

        public void SavePosition(string positionOf, System.Drawing.Point position) {

            var positionElement = m_xmlDoc.Elements(ROOT_TAG_NAME).Elements(POSITION_TAG).
                Where(x =>
                    (x.Element(POSITION_OFF_TAG).Value == positionOf)).FirstOrDefault();

            if (positionElement == null) {
                // if not exist, create new
                positionElement = new XElement(POSITION_TAG);
                positionElement.Add(new XElement(POSITION_OFF_TAG, positionOf));
                positionElement.Add(new XElement(X_TAG, position.X));
                positionElement.Add(new XElement(Y_TAG, position.Y));
                m_xmlDoc.Element(ROOT_TAG_NAME).Add(positionElement);
            } else {
                // if exist, Update
                positionElement.Element(X_TAG).Value = position.X.ToString();
                positionElement.Element(Y_TAG).Value = position.Y.ToString();
            }

        }

        public Point GetPosition(string positionOf) {
            var positionElement = m_xmlDoc.Elements(ROOT_TAG_NAME).Elements(POSITION_TAG).
               Where(x =>
                   (x.Element(POSITION_OFF_TAG).Value == positionOf)).FirstOrDefault();
            if (positionElement != null) {
                return new Point(int.Parse(positionElement.Element(X_TAG).Value), int.Parse(positionElement.Element(Y_TAG).Value));
            }

            return new Point(Constants.DEFAULT_POSITION_VALUE, Constants.DEFAULT_POSITION_VALUE);
        }

        #endregion

        #region Private functions

        private void CreateXmlDataFile() {
            if (!Directory.Exists(AppDataFolder)) {
                Directory.CreateDirectory(AppDataFolder);
            }
            using (var file = File.Create(AppDataFile)) {
                XmlWriter xmlWriter = XmlWriter.Create(file);
                xmlWriter.WriteStartDocument();
                xmlWriter.WriteStartElement(ROOT_TAG_NAME);
                xmlWriter.WriteEndElement();
                xmlWriter.WriteEndDocument();
                xmlWriter.Close();
            }
        }

        private string BoolToString(bool boolValue){
            return boolValue ? "TRUE" : "FALSE";
        }

        private bool StringToBoolOrDefault(XElement xElement) {
            string boolString = xElement != null ? xElement.Value : string.Empty;
            return !string.IsNullOrEmpty(boolString) && boolString.Equals("TRUE", StringComparison.OrdinalIgnoreCase);
        }

        #endregion
    }
}
